﻿using System.Collections.Generic;
using System.Drawing;

using GViz.Types;

namespace GViz.Charts 
{
    public class Wave : IChart 
    {
        public List<DataSet> Data {
            get; private set;
        }
        
        public int Width {
            get; private set;
        }

        public int Height {
            get; private set;
        }

        public int Intervals {
            get; private set;
        }

        public int HorizontalZoom {
            get {
                return this.Width / this.Intervals;
            }
        }

        public int VerticalZoom {
            get {
                return this.Height / this.max;
            }
        }

        public bool Refresh {
            get; private set;
        }

        private int         max;
        private Graphics    graphics;
        private Bitmap      bitmap;

        private Color       intervalColor;
        private Color       backgroundColor;
        private Color       labelColor;

        public Wave(int width, int height) {
            this.Width = width;
            this.Height = height;
        }

        public Wave(List<DataSet> data, int width, int height, int intervals) {
            this.Data = data;
            this.Width = width;
            this.Height = height;
            this.Refresh = true;
            this.Intervals = intervals;

            this.max = 0;
            this.bitmap = new Bitmap(width, height);
            this.graphics = Graphics.FromImage(this.bitmap);

            this.intervalColor = Color.FromArgb(10, 10, 10);
            this.backgroundColor = Color.FromKnownColor(KnownColor.White);
            
        }

        public Bitmap Render() {
            // search for maximum element (we'll scale the image to this height)
            int[] stats = new int[this.Intervals];

            foreach (DataSet dataSet in this.Data) {
                for (int i = 0; i < this.Intervals; ++i) {
                    stats[i] += dataSet.Data[i];
                }
                if (dataSet.Max > this.max) {
                    this.max = dataSet.Max;
                }
            }
            
            // some kind of freaky error occurs
            if (this.max == 0) {
                return this.bitmap;
            }

            // chart background
            SolidBrush backgroundBrush = new SolidBrush(this.backgroundColor);
            this.graphics.FillRectangle(backgroundBrush, new Rectangle(0, 0, this.Width, this.Height));

            // intervals
            Pen iPen = new Pen(this.intervalColor);
            for (int i = 1; i < this.Intervals - 1; ++i) {
                int w = i * this.HorizontalZoom;

                this.graphics.DrawLine(iPen, new Point(w, 0), new Point(w, this.Height));
            }

            // do the wave
            int[] heights = new int[this.Intervals];

            foreach (DataSet dataSet in this.Data) {
                // polygon nodes
                Point[] points = new Point[this.Intervals * 2];

                for (int i = 0, point = 0; i < this.Intervals; ++i, ++point) {
                    Point from = new Point(i * this.HorizontalZoom, heights[i] * this.VerticalZoom + ((this.max - stats[i]) * this.VerticalZoom) / 2);
                    Point to = new Point(i * this.HorizontalZoom, heights[i] * this.VerticalZoom + dataSet.Data[i] * this.VerticalZoom + ((this.max - stats[i]) * this.VerticalZoom) / 2);

                    points[point] = from;
                    points[this.Intervals * 2 - point - 1] = to;

                    heights[i] += dataSet.Data[i];
                }

                // do draw
                SolidBrush polyBrush = new SolidBrush(dataSet.Color);
                graphics.FillClosedCurve(polyBrush, points);
            }

            return this.bitmap;
        }
    }
}
